package com.rfid.project.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;

import biz.util.*;

import com.rfid.project.model.*;
import com.rfid.project.util.NumberUtil;
import com.rfid.project.dao.*;
import com.rfid.project.exception.CannotUpdateException;
import com.mysema.query.BooleanBuilder;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
@Transactional
public class ProjectTaskFinishApplyService{

	@Autowired
	private ProjectTaskFinishApplyDao projectTaskFinishApplyDao;
	
	private QProjectTaskFinishApply $ = QProjectTaskFinishApply.projectTaskFinishApply;
	
	private QProjectTask $_projectTask = QProjectTask.projectTask;
	
	private ProjectTaskDao projectTaskDao;

	@Autowired
	private ProjectTaskPersonDao projectTaskPersonDao;

	private QProjectTaskPerson $_projectTaskPerson = QProjectTaskPerson.projectTaskPerson;

	@Autowired
	public void setProjectTaskPersonDao(ProjectTaskPersonDao projectTaskPersonDao) {
		this.projectTaskPersonDao = projectTaskPersonDao;
	}

	@Autowired
	private ProjectMemberDao projectMemberDao;

	private QProjectMember $_projectMember = QProjectMember.projectMember;

	@Autowired
	public void setProjectMemberDao(ProjectMemberDao projectMemberDao) {
		this.projectMemberDao = projectMemberDao;
	}

	@Autowired
	private ProjectDao projectDao;
	
	private QProject $_project = QProject.project;
	
	@Autowired
	public void setProjectDao(ProjectDao projectDao) {
		this.projectDao = projectDao;
	}
	
	@Autowired
	public void setProjectTaskDao(ProjectTaskDao projectTaskDao) {
		this.projectTaskDao = projectTaskDao;
	}
	
	@Autowired
	public void setProjectTaskFinishApplyDao(ProjectTaskFinishApplyDao projectTaskFinishApplyDao) {
		this.projectTaskFinishApplyDao = projectTaskFinishApplyDao;
	}
	
	public List<ProjectTaskFinishApply> findAll(){
		return ListUtil.toList(projectTaskFinishApplyDao.findAll());
	}
	
	public ProjectTaskFinishApply findOne(Long id){
		return this.projectTaskFinishApplyDao.findOne(id);
	}
				
	public List<ProjectTaskFinishApply> findAll(
		Long applyPersonId,
		String applyDescription,
		Date applyTimeBegin,
		Date applyTimeEnd,
		Long checkPersonId,
		String checkComment,
		Date checkTimeBegin,
		Date checkTimeEnd,
		String status,
		Long projectTaskId,
		String orderByAttribute	){
		BooleanBuilder condition = new BooleanBuilder();
		
		if(IdUtil.isNotEmpty(applyPersonId)){
			condition.and($.applyPerson.id.eq(applyPersonId));
		}
		
		if(StringUtil.isNotEmpty(applyDescription)){
			condition.and($.applyDescription.contains(applyDescription));
		}
		
		if(applyTimeBegin != null){
			condition.and($.applyTime.after(applyTimeBegin));
		}
		
		if(applyTimeEnd != null){
			condition.and($.applyTime.before(applyTimeEnd));
		}
		
		if(IdUtil.isNotEmpty(checkPersonId)){
			condition.and($.checkPerson.id.eq(checkPersonId));
		}
		
		if(StringUtil.isNotEmpty(checkComment)){
			condition.and($.checkComment.contains(checkComment));
		}
		
		if(checkTimeBegin != null){
			condition.and($.checkTime.after(checkTimeBegin));
		}
		
		if(checkTimeEnd != null){
			condition.and($.checkTime.before(checkTimeEnd));
		}
		
		if(StringUtil.isNotEmpty(status)){
			condition.and($.status.contains(status));
		}
		
		if(IdUtil.isNotEmpty(projectTaskId)){
			condition.and($.projectTaskPerson.projectTask.id.eq(projectTaskId));
		}
		
		
		return ListUtil.toList(projectTaskFinishApplyDao.findAll(condition));
	}		

	public Page<ProjectTaskFinishApply> findAll(
			Long projectId,
			Long projectTaskPersonId,
			Long applyPersonId,
			String applyDescription,
			Date applyTimeBegin,
			Date applyTimeEnd,
			Long checkPersonId,
			String checkComment,
			Date checkTimeBegin,
			Date checkTimeEnd,
			String status,
			Long projectTaskId,
			int pageNumber, int pageSize,String sortAttribute,String orderDirection) {
			BooleanBuilder condition = new BooleanBuilder();
	
			if(IdUtil.isNotEmpty(projectId)){
				BooleanBuilder der = new BooleanBuilder();
				der.and($_projectTask.project.id.eq(projectId));
				condition.and($.projectTaskPerson.projectTask.in(ListUtil.toList((this.projectTaskDao.findAll(der)))));
			}
			if(IdUtil.isNotEmpty(projectTaskPersonId)){
				condition.and(this.$.projectTaskPerson.id.eq(projectTaskPersonId));
			}
			if(IdUtil.isNotEmpty(applyPersonId)){
				condition.and($.applyPerson.id.eq(applyPersonId));
			}
			if(StringUtil.isNotEmpty(applyDescription)){
				condition.and($.applyDescription.contains(applyDescription));
			}
			if(applyTimeBegin != null){
				condition.and($.applyTime.after(applyTimeBegin));
			}
			
			if(applyTimeEnd != null){
				condition.and($.applyTime.before(applyTimeEnd));
			}
			if(IdUtil.isNotEmpty(checkPersonId)){
				condition.and($.checkPerson.id.eq(checkPersonId));
			}
			if(StringUtil.isNotEmpty(checkComment)){
				condition.and($.checkComment.contains(checkComment));
			}
			if(checkTimeBegin != null){
				condition.and($.checkTime.after(checkTimeBegin));
			}
			
			if(checkTimeEnd != null){
				condition.and($.checkTime.before(checkTimeEnd));
			}
			if(StringUtil.isNotEmpty(status)){
				condition.and($.status.contains(status));
			}
			if(IdUtil.isNotEmpty(projectTaskId)){
				condition.and($.projectTaskPerson.projectTask.id.eq(projectTaskId));
			}
	
			Sort sortObject = null;
			if(StringUtil.isEmpty(sortAttribute)){
				sortObject = new Sort(Direction.DESC, "id");
			}else{
				sortObject = new Sort(Direction.fromStringOrNull(orderDirection),sortAttribute);
			}
			
			PageRequest pageRequest = new PageRequest(pageNumber - 1, pageSize, sortObject);
			return projectTaskFinishApplyDao.findAll(condition, pageRequest);
	}
	
	
	
	public ProjectTaskFinishApply getProjectTaskFinishApply(Long id){
		return projectTaskFinishApplyDao.getOne(id);
	}
	
	public void deleteProjectTaskFinishApply(Long id){
		projectTaskFinishApplyDao.delete(id);
	}

	public void saveProjectTaskFinishApply(ProjectTaskFinishApply projectTaskFinishApply) {
		if(null == projectTaskFinishApply.getApplyTime()){
			projectTaskFinishApply.setApplyTime(DateUtil.nowDate());
		}
		
		ProjectTaskPerson projectTaskPerson = this.projectTaskPersonDao.findOne(projectTaskFinishApply.getProjectTaskPerson().getId());
		projectTaskPerson.setStatus(projectTaskFinishApply.getStatus());
		projectTaskPerson.setOriginalConsumeWorktime(projectTaskFinishApply.getProjectTaskPerson().getOriginalConsumeWorktime());
		
		this.projectTaskFinishApplyDao.save(projectTaskFinishApply);
		this.projectTaskPersonDao.save(projectTaskPerson);
	}

	public List<ProjectTaskFinishApply> findByStatus(People people, Long projectMemberType, String status) {
		BooleanBuilder condition = new BooleanBuilder();
		condition.and(this.$_projectMember.person.id.eq(people.getId()));
		condition.and(this.$_projectMember.projectMemberType.id.eq(projectMemberType));
		Iterable<ProjectMember> projectMembers = this.projectMemberDao.findAll(condition);
		Set<Long> ids = new HashSet<Long>();
		for (ProjectMember projectMember : projectMembers) {
			ids.add(projectMember.getProject().getId());
		}
		
		if (!ids.isEmpty()) {
			condition = new BooleanBuilder();
			condition.and(this.$_projectTask.project.id.in(ids));
			Iterable<ProjectTask> projectTasks = this.projectTaskDao.findAll(condition);
			ids.clear();
			for (ProjectTask projectTask : projectTasks) {
				ids.add(projectTask.getId());
			}
			
			if (!ids.isEmpty()) {
				condition = new BooleanBuilder();
				condition.and(this.$.projectTaskPerson.projectTask.id.in(ids));
				if (StringUtil.isNotEmpty(status)) {
					condition.and($.status.eq(status));
				}
				return ListUtil.toList(projectTaskFinishApplyDao.findAll(condition));
			}
		}
		return null;
	}
	
	public void checkProjectTaskFinishApply(ProjectTaskFinishApply projectTaskFinishApply) throws CannotUpdateException{
		ProjectTaskFinishApply sourceProjectTaskFinishApply = this.projectTaskFinishApplyDao.findOne(projectTaskFinishApply.getId());
		if(!ProcessStatus.FINISH_APPLY.equals(sourceProjectTaskFinishApply.getStatus())){
			throw new CannotUpdateException("您处理的项目任务完成申请已发生变化，请刷新后再操作！");
		}
		sourceProjectTaskFinishApply.setStatus(projectTaskFinishApply.getStatus());
		sourceProjectTaskFinishApply.setCheckPerson(projectTaskFinishApply.getCheckPerson());
		sourceProjectTaskFinishApply.setCheckComment(projectTaskFinishApply.getCheckComment());
		sourceProjectTaskFinishApply.setCheckTime(DateUtil.nowDate());
		
		ProjectTaskPerson projectTaskPerson = sourceProjectTaskFinishApply.getProjectTaskPerson();
		projectTaskPerson.setStatus(projectTaskFinishApply.getProjectTaskPerson().getStatus());
		if(ProcessStatus.EXAMINE_SUCCESS.equals(projectTaskFinishApply.getStatus())){
			projectTaskPerson.setConfirmConsumeWorktime(projectTaskFinishApply.getProjectTaskPerson().getConfirmConsumeWorktime());
			projectTaskPerson.setActualFinishDate(sourceProjectTaskFinishApply.getApplyTime());
			
			ProjectTask projectTask = projectTaskPerson.getProjectTask();
			BooleanBuilder condition = new BooleanBuilder();
			condition.and(this.$_projectTaskPerson.projectTask.id.eq(projectTask.getId()));
			condition.and(this.$_projectTaskPerson.status.notIn(ProcessStatus.EXAMINE_SUCCESS));
			projectTask.setActualWorktime(NumberUtil.transition(projectTask.getActualWorktime()) + NumberUtil.transition(projectTaskFinishApply.getProjectTaskPerson().getConfirmConsumeWorktime()));
			if(this.projectTaskPersonDao.count(condition) < 1){
				projectTask.setStatus(ProcessStatus.SUCCESS);
				projectTask.setActualFinishDate(sourceProjectTaskFinishApply.getApplyTime());
				
				Project project = projectTask.getProject();
				project.setActualConsumeWorktime(NumberUtil.transition(project.getActualConsumeWorktime()) + NumberUtil.transition(projectTask.getActualWorktime()));
				this.projectDao.save(project);
			}
			
			this.projectTaskDao.save(projectTask);
			this.increasePersonPredictConsumeWorktimeByTask(projectTaskPerson);
		}
		
		this.projectTaskFinishApplyDao.save(sourceProjectTaskFinishApply);
		this.projectTaskPersonDao.save(projectTaskPerson);
	}
	
	private void increasePersonPredictConsumeWorktimeByTask(ProjectTaskPerson projectTaskPerson){
		BooleanBuilder condition = new BooleanBuilder();
		condition.and(this.$_projectMember.project.id.eq(projectTaskPerson.getProjectTask().getProject().getId()));
		condition.and(this.$_projectMember.person.id.eq(projectTaskPerson.getPeople().getId()));
		ProjectMember projectMember = this.projectMemberDao.findOne(condition);
		projectMember.setActualConsumeWorktime(NumberUtil.transition(projectMember.getActualConsumeWorktime()) + NumberUtil.transition(projectTaskPerson.getConfirmConsumeWorktime()));
		
		this.projectMemberDao.save(projectMember);
	}

}
		
